package com.gusto.samples.movielens;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gusto.engine.beans.exceptions.ResCreationException;
import com.gusto.engine.repository.exception.RepositoryException;
import com.gusto.engine.repository.service.RepositoryService;
import com.gusto.engine.semsim.exceptions.ConfigException;
import com.gusto.engine.semsim.exceptions.SimilarityException;
import com.gusto.engine.semsim.neighborhood.SemNeighborhoodService;
import com.gusto.engine.semsim.service.SimilarityService;
import com.gusto.utils.cli.SemSimCLI;
import com.gusto.utils.semantic.SemanticService;
import com.hp.hpl.jena.db.DBConnection;

public class TestMovieLens extends SemSimCLI {
	
	private static Logger log = Logger.getLogger(TestMovieLens.class);
	 
	private String baseURI = "http://www.ini-cerist.dz/movie-lens.owl#";
	
	private static ApplicationContext factory = new ClassPathXmlApplicationContext("config/movielens/movielens-semsim-*.xml");
	private static SimilarityService similarityService = (SimilarityService)factory.getBean("similarityService");
	private static RepositoryService modelService = (RepositoryService)factory.getBean("modelService");
	
	private static SemanticService semanticService = (SemanticService)factory.getBean("semanticService");
	private static SemNeighborhoodService neighborhoodService = (SemNeighborhoodService)factory.getBean("semanticNeighborhoodService");
	private static DBConnection databaseConnection = (DBConnection)factory.getBean("semsim_databaseConnection");
	
	public TestMovieLens(SimilarityService semanticSimilarity, RepositoryService modelService, SemanticService semanticService) {
		super(semanticSimilarity, modelService, semanticService);
	}

	public static void main(String[] args) throws SimilarityException, ResCreationException, RepositoryException, SQLException, IOException, ConfigException {
		TestMovieLens testMovielens2 = new TestMovieLens(similarityService, modelService, semanticService);
		testMovielens2.init();
		
		//testMovielens2.execute(args);
		testMovielens2.calculateItemSimilarities();
	}
	
	private void init() throws SQLException {
		Connection conn = databaseConnection.getConnection();
		
		Statement stmt1 = conn.createStatement();
		ResultSet rset = stmt1.executeQuery("select count(*) from jena_g2t1_stmt ");
		rset.next();
		Integer count = rset.getInt(1);
		System.out.println(count);
		stmt1.close();
		
		if (count.equals(0)) {
		//if (true) {
			Statement stmt = conn.createStatement();
			stmt.execute("insert into jena_g2t1_stmt select * from jena_g2t1_stmt_a " +
					"where not (Prop like '%hasActor%' or Prop like '%hasCast%' " +
					"or Prop like '%hasCharacterName%' or Prop like '%hasRank%' " +
					"or Prop like '%hasMPAAReason%' or Prop like '%hasMPAAReason%' " +
					"or Prop like '%hasName%' " +
					//"or Prop like '%Uv::http://www.w3.org/1999/02/22-rdf-syntax-ns#type:%') " +
					"or Subj like '%anguage%' or Obj like '%anguage%' or Obj like '%Romance%' or Obj like '%Inuit%' or Obj like '%MalayoPolynesian%' or Obj like '%Inuit%'");
			//conn.commit();
			stmt.close();
			System.out.println("Loading");
		}
		
		Connection conn2 = databaseConnection.getConnection();
		Statement stmt2 = conn2.createStatement();
		ResultSet rset2 = stmt2.executeQuery("select * from jena_g2t1_stmt");
		while (rset2.next()) {}
		//conn.commit();
		stmt2.close();
		
		/**
		model = modelMaker.openModel(modelName, true);
		Model m2 = ModelFactory.createMemModelMaker().openModel();
		m2.add(model);
		/**/
	}
	
	
	@Override
	public void help() {
		System.out.println("help");
		System.out.println("-----------------------------");
		System.out.println("query data/movieCompany.rq");
		System.out.println("resource M_102");
		
		System.out.println("similarity M_168 M_6");
		System.out.println("similarity M_127 M_187");
		System.out.println("similarity M_427 M_187");
		System.out.println("similarity L_Swedish L_German ");
		System.out.println("           (Norwegian Danish Icelandic English Dutch Afrikaans Japanese Mandarin)");
		System.out.println("           (French Italian Spanish Portuguese Romanian Arabic Turkish)");
		
		System.out.println("neighborhood M_168");
		
		System.out.println("similarity U_86 U_44");
	}

	@Override
	public void load(String file) {
		//semanticSimilarityService.loadOntologyFromFile("movielens", file);
		//semanticSimilarityService.loadOntologyFromFile("movielens", file, true);
	}
	
	@Override
	public void resource(String resource) {
		semanticService.getResourceProperties("http://www.ini-cerist.dz/movie-lens.owl#" + resource, null);
		//semanticSimilarityService.getResourceProperties("http://www.ini-cerist.dz/movie-lens.owl#M_102", "http://www.ini-cerist.dz/movie-lens.owl#hasKeyWords");
	}
	
	@Override
	public void similarity(String res1, String res2) throws SimilarityException, ResCreationException, RepositoryException {
		if (res1.startsWith("L_") && res2.startsWith("L_")) {
			System.out.println(getLanguageSimilarity(res1.substring(2), res2.substring(2)));
		}
		else if (res1.startsWith("U_") && res2.startsWith("U_")) {
			System.out.println(getUserSimilarity(Integer.parseInt(res1.substring(2)), Integer.parseInt(res2.substring(2))));
		}
		else if (res1.startsWith("M_") && res2.startsWith("M_")) {
			System.out.println(getMovieSimilarity(Integer.parseInt(res1.substring(2)), Integer.parseInt(res2.substring(2))));
		}
	}
	
	@Override
	public void neighborhood(String resource) throws SimilarityException {
		if (resource.startsWith("U_")) {
			System.out.println(neighborhoodService.getNeighborhood("user", resource.substring(2), 0.0, 100));
		}
		else if (resource.startsWith("M_")) {
			System.out.println(neighborhoodService.getNeighborhood("movie", resource.substring(2), 0.0, 100));
		}
	}
	
	
	
	
	
	private Double getLanguageSimilarity(String lang1, String lang2) throws SimilarityException, ResCreationException, RepositoryException {
		long start = System.currentTimeMillis();
		Double sim = similarityService.getSimilarity("language", modelService.getResource(baseURI + "" + lang1), modelService.getResource(baseURI + "" + lang2));
		log.info("Dist. User " + (System.currentTimeMillis() - start) + " (" + lang1 + "-" + lang2 + ") " + sim);
		return sim;
	}
	
	private Double getUserSimilarity(int user1, int user2) throws SimilarityException, ResCreationException, RepositoryException {
		long start = System.currentTimeMillis();
		Double sim = similarityService.getSimilarity("user", modelService.getResource(baseURI + "_" + user1), modelService.getResource((Object)baseURI + "_" + user2));
		log.info("Dist. User " + (System.currentTimeMillis() - start) + " (" + user1 + "-" + user2 + ") " + sim);
		return sim;
	}
	
	private Double getMovieSimilarity(int movie1, int movie2) throws SimilarityException, ResCreationException, RepositoryException {
		long start = System.currentTimeMillis();
		Double sim = similarityService.getSimilarity("movie", modelService.getResource(baseURI + "M_" + movie1), modelService.getResource((Object)baseURI + "M_" + movie2));
		log.info("Dist. Item " + (System.currentTimeMillis() - start) + " (" + movie1 + "-" + movie2 + ") " + sim);
		return sim;
	}
	
	public void calculateUserSimilarities() throws SimilarityException, ResCreationException, RepositoryException {
		for (int i=1; i<=945; i++) {
			for (int j=1; j<=945; j++) {
				if ((i+"").compareTo(j+"") >= 0) {
					getUserSimilarity(i, j);
				}
			}
		}
	}
	
	public void calculateItemSimilarities() throws SimilarityException, ResCreationException, RepositoryException {
		for (int i=1; i<=1682; i++) {
			for (int j=1; j<=1682; j++) {
				if ((i+"").compareTo(j+"") >= 0) {
					getMovieSimilarity(i, j);
				}
			}
		}
	}
}
